use std::collections::BTreeMap;

use tracing::debug;

use crate::ast_define::MetaInfo;

/// 类型系统
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
    /// int类型
    Int,
    /// void类型（仅用于函数返回值）
    Void,
    /// 数组类型，存储维度信息
    Array(usize),
    /// 函数类型，存储参数类型和返回类型
    Function {
        params: Vec<Symbol>,
        return_type: Box<Type>,
    },
}

impl Type {
    /// 检查两个类型是否兼容（用于赋值检查）
    pub fn is_assignable_from(&self, other: &Type) -> bool {
        match (self, other) {
            (Type::Int, Type::Int) => true,
            (Type::Array(dims1), Type::Array(dims2)) => {
                // 根据lab3要求，允许多维数组间的赋值
                // a[1] = b; 其中a是int[3][3][3], b是int[2][2]是合法的
                dims1 == dims2
            }
            _ => false,
        }
    }

    /// 检查是否为数组类型
    pub fn is_array(&self) -> bool {
        matches!(self, Type::Array(_))
    }

    /// 检查是否为函数类型
    pub fn is_function(&self) -> bool {
        matches!(self, Type::Function { .. })
    }

    /// 获取数组元素类型（去掉一维）
    pub fn array_element_type(&self) -> Option<Type> {
        match self {
            Type::Array(dims) if *dims > 1 => Some(Type::Array(dims - 1)),
            Type::Array(dims) if *dims == 1 => Some(Type::Int),
            _ => None,
        }
    }
}

/// 符号类型
#[derive(Debug, Clone, PartialEq)]
pub enum SymbolType {
    /// 变量符号
    Variable(Type),
    /// 常量符号
    Constant(Type),
    /// 函数符号
    Function(Type),
}

impl SymbolType {
    pub fn get_type(&self) -> &Type {
        match self {
            SymbolType::Variable(t) | SymbolType::Constant(t) | SymbolType::Function(t) => t,
        }
    }

    pub fn is_function(&self) -> bool {
        matches!(self, SymbolType::Function(_))
    }
}

/// 符号表项
#[derive(Debug, Clone, PartialEq)]
pub struct Symbol {
    pub name: String,
    pub symbol_type: SymbolType,
    pub location: MetaInfo,
}

impl Symbol {
    pub fn new(name: String, symbol_type: SymbolType, location: MetaInfo) -> Self {
        Self {
            name,
            symbol_type,
            location,
        }
    }

    pub fn get_type(&self) -> &Type {
        match &self.symbol_type {
            SymbolType::Variable(t) | SymbolType::Constant(t) | SymbolType::Function(t) => t,
        }
    }
}

/// 作用域类型
#[derive(Debug, Clone, PartialEq)]
pub enum ScopeType {
    Global,
    Function(String), // 函数名
    Block,
}

/// 作用域
#[derive(Debug)]
pub struct Scope {
    pub symbols: BTreeMap<String, Symbol>,
    pub parent: Option<usize>,
    pub scope_type: ScopeType,
}

impl Scope {
    pub fn new(scope_type: ScopeType, parent: Option<usize>) -> Self {
        Self {
            symbols: BTreeMap::new(),
            parent,
            scope_type,
        }
    }
}

/// 符号表
#[derive(Debug)]
pub struct SymbolTable {
    pub scopes: Vec<Scope>,
    pub current_scope: usize,
}

impl SymbolTable {
    pub fn new() -> Self {
        let mut scopes = vec![Scope::new(ScopeType::Global, None)];
        Self {
            scopes,
            current_scope: 0,
        }
    }

    /// 进入新作用域
    pub fn enter_scope(&mut self, scope_type: ScopeType) {
        let parent = Some(self.current_scope);
        let scope = Scope::new(scope_type, parent);
        self.scopes.push(scope);
        self.current_scope = self.scopes.len() - 1;
    }

    /// 退出当前作用域
    pub fn exit_scope(&mut self) {
        if let Some(parent) = self.scopes[self.current_scope].parent {
            self.current_scope = parent;
        }
    }

    /// 在当前作用域中定义符号
    pub fn define(&mut self, symbol: Symbol) {
        self.scopes[self.current_scope]
            .symbols
            .insert(symbol.name.clone(), symbol);
    }

    pub fn check_redefine(&self, name: &str, r#type: &SymbolType) -> Result<(), ()> {
        // 检查当前作用域中是否已存在同名符号
        if self.scopes[self.current_scope].symbols.contains_key(name) {
            return Err(());
        }
        Ok(())
    }

    /// 查找符号（从当前作用域向上查找）
    pub fn lookup(&self, name: &str) -> Option<&Symbol> {
        let mut current = self.current_scope;

        loop {
            if let Some(symbol) = self.scopes[current].symbols.get(name) {
                return Some(symbol);
            }

            if let Some(parent) = self.scopes[current].parent {
                current = parent;
            } else {
                break;
            }
        }

        None
    }

    /// 在当前作用域中查找符号
    pub fn lookup_current_scope(&self, name: &str) -> Option<&Symbol> {
        self.scopes[self.current_scope].symbols.get(name)
    }

    /// 获取当前作用域类型
    pub fn current_scope_type(&self) -> &ScopeType {
        &self.scopes[self.current_scope].scope_type
    }

    /// 检查当前是否在函数作用域中
    pub fn in_function_scope(&self) -> bool {
        let mut current = self.current_scope;

        loop {
            match &self.scopes[current].scope_type {
                ScopeType::Function(_) => return true,
                ScopeType::Global => return false,
                ScopeType::Block => {
                    if let Some(parent) = self.scopes[current].parent {
                        current = parent;
                    } else {
                        return false;
                    }
                }
            }
        }
    }

    /// 获取当前函数名（如果在函数作用域中）
    pub fn current_function_name(&self) -> Option<&String> {
        let mut current = self.current_scope;

        loop {
            match &self.scopes[current].scope_type {
                ScopeType::Function(name) => return Some(name),
                ScopeType::Global => return None,
                ScopeType::Block => {
                    if let Some(parent) = self.scopes[current].parent {
                        current = parent;
                    } else {
                        return None;
                    }
                }
            }
        }
    }
}

impl Default for SymbolTable {
    fn default() -> Self {
        Self::new()
    }
}
